package cn.edu.ptu.jobfairs.core;

import cn.edu.ptu.jobfairs.basic.common.Errors;
import cn.edu.ptu.jobfairs.basic.common.VisibleException;
import cn.edu.ptu.jobfairs.core.utils.SqlBuilder;
import cn.edu.ptu.jobfairs.repository.IdDao;
import cn.edu.ptu.jobfairs.repository.mapper.SqlMapper;
import com.google.common.base.CaseFormat;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static cn.edu.ptu.jobfairs.basic.common.Errors.SERVER_ERROR;


/**
 * Created by Lin Chenxiao on 2020-05-27
 **/
@Slf4j
@Component
public class SqlHandler {
    @Resource
    private SqlMapper sqlMapper;

    public boolean exists(SqlBuilder sql) {
        return sqlMapper.select(sql.toString()) != null;
    }

    public void notExists(SqlBuilder countSql) {
        Long count = sqlMapper.count(countSql.toString());
        if (count != null && count > 0)
            throw new VisibleException(Errors.RECORD_EXISTS);
    }

    public Integer create(SqlBuilder sql) {
        IdDao idDao = new IdDao();
        int i = sqlMapper.create(sql.toString(), idDao);
        if (i <= 0 || idDao.getId() == null) throw new VisibleException(Errors.DATABASE_ERROR);
        return idDao.getId();
    }

    public void insert(SqlBuilder sql) {
        int i = sqlMapper.insert(sql.toString());
        if (i <= 0) throw new VisibleException(Errors.DATABASE_ERROR);
    }

    public int delete(SqlBuilder sql) {
        return sqlMapper.delete(sql.toString());
    }

    public void deleteOne(SqlBuilder sql) {
        int i = sqlMapper.delete(sql.toString());
        if (i <= 0) throw new VisibleException(Errors.DATABASE_ERROR);
    }

    public int update(SqlBuilder sql) {
        return sqlMapper.update(sql.toString());
    }

    public void updateOne(SqlBuilder sql) {
        int i = sqlMapper.update(sql.toString());
        if (i <= 0) throw new VisibleException(Errors.RECORD_NOT_EXISTS);
    }

    public long count(SqlBuilder countSql) {
        Long count = sqlMapper.count(countSql.toString());
        return count == null ? 0 : count;
    }

    public <T> List<T> selectAll(SqlBuilder sql, Class<T> clazz) {
        List<Map<String, Object>> maps = sqlMapper.multiSelect(sql.toString());
        List<T> list = new ArrayList<>();
        if (CollectionUtils.isEmpty(maps)) return list;
        for (Map<String, Object> map : maps) {
            T obj = to(map, clazz);
            if (obj != null) list.add(obj);
        }
        return list;
    }

    public <T> T select(SqlBuilder sql, Class<T> clazz) {
        Map<String, Object> map = sqlMapper.select(sql.toString());
        return to(map, clazz);
    }

    private static <T> T to(Map<String, Object> map, Class<T> clazz) {
        if (map == null) return null;
        try {
            T obj = clazz.newInstance();
            Class<?> tClass = clazz;
            Map<String, Field> fieldMap = new HashMap<>();
            do {
                for (Field field : tClass.getDeclaredFields()) {
                    fieldMap.putIfAbsent(field.getName(), field);
                }
                tClass = tClass.getSuperclass();
            }
            while (tClass != Object.class);
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                Object val = entry.getValue();
                if (val == null || entry.getKey().endsWith("_crc")) continue;
                Field field = fieldMap.get(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, entry.getKey()));
                if (field != null) {
                    field.setAccessible(true);
                    field.set(obj, val);
                }
            }
            return obj;
        } catch (Exception e) {
            log.error("sql转换对象出错", e);
            throw new VisibleException(SERVER_ERROR, "数据库反序列化错误");
        }
    }
}
